{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Defining Multiple Subdomains\n",
    "\n",
    "One of the features in OpenPNM is the ability to model heterogeneous materials by applying different pore-scale models to different regions.  This is done by (a) creating a unique **Geometry** object for each region (i.e. small pores vs big pores) and (b) creating unique **Physics** object for each region as well (i.e. Knudsen diffusion vs Fickian diffusion).  One consequence of this segregation of properties is that a *single* array containing values for all locations in the domain does not exist.  OpenPNM offers a shortcut for this, known as ``interleave_data``, which happens *automatically*, and makes it possible to query **Geometry** properties via the **Network** object, and **Physics** properties from the associated **Phase** object:\n",
    "\n",
    "Let's demonstrate this by creating a network and assigning two separate geometries to each half of the network:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2021-06-24T11:25:13.386101Z",
     "iopub.status.busy": "2021-06-24T11:25:13.384478Z",
     "iopub.status.idle": "2021-06-24T11:25:13.964400Z",
     "shell.execute_reply": "2021-06-24T11:25:13.963829Z"
    }
   },
   "outputs": [],
   "source": [
    "import openpnm as op"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2021-06-24T11:25:13.972408Z",
     "iopub.status.busy": "2021-06-24T11:25:13.969085Z",
     "iopub.status.idle": "2021-06-24T11:25:13.976698Z",
     "shell.execute_reply": "2021-06-24T11:25:13.977198Z"
    }
   },
   "outputs": [],
   "source": [
    "pn = op.network.Cubic([5, 5, 5])\n",
    "geo1 = op.geometry.GenericGeometry(network=pn, pores=range(0, 75),\n",
    "                                   throats=range(0, 150))\n",
    "geo2 = op.geometry.GenericGeometry(network=pn, pores=range(75, 125),\n",
    "                                   throats=range(150, 300))\n",
    "geo1['pore.diameter'] = 1.0\n",
    "geo2['pore.diameter'] = 0.1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Each of the Geometry objects has a 'pore.diameter' array with different values.  To obtain a single array of 'pore.diameter' with values in the correct locations, we can use the Network as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2021-06-24T11:25:13.982468Z",
     "iopub.status.busy": "2021-06-24T11:25:13.981793Z",
     "iopub.status.idle": "2021-06-24T11:25:13.985983Z",
     "shell.execute_reply": "2021-06-24T11:25:13.986467Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1.  1.  1.  1.  1.  0.1 0.1 0.1 0.1 0.1]\n"
     ]
    }
   ],
   "source": [
    "Dp = pn['pore.diameter']\n",
    "print(Dp[70:80])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As can be seen, the 'pore.diameter' array contains values from both Geometry objects, and they are in their correction locations in terms of the domain number system.  This is referred to as ``interleave_data``.  It also works to obtain Physics values via their associated Phase object.\n",
    "\n",
    "Interleaving of data also works in the reverse direction, so that data only present on the network can be accessed via the Geometry objects:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2021-06-24T11:25:13.991348Z",
     "iopub.status.busy": "2021-06-24T11:25:13.990613Z",
     "iopub.status.idle": "2021-06-24T11:25:13.994245Z",
     "shell.execute_reply": "2021-06-24T11:25:13.994789Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.5 0.5 0.5]\n",
      " [0.5 0.5 1.5]\n",
      " [0.5 0.5 2.5]]\n"
     ]
    }
   ],
   "source": [
    "coords = geo1['pore.coords']\n",
    "print(coords[0:3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, ``interleave_data`` works between objects of the same type, so that if 'pore.volume' is present on one but not another Geometry object, you will get an array of NaNs when asking for it on the object that does not have it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2021-06-24T11:25:14.000868Z",
     "iopub.status.busy": "2021-06-24T11:25:14.000097Z",
     "iopub.status.idle": "2021-06-24T11:25:14.004911Z",
     "shell.execute_reply": "2021-06-24T11:25:14.004240Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[nan nan nan nan nan]\n"
     ]
    }
   ],
   "source": [
    "geo1['pore.volume'] = 3.0\n",
    "print(geo2['pore.volume'][:5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Points to Note\n",
    "\n",
    "* Data **cannot** be written in this way, so that you cannot write 'pore.diameter' values to the Network if 'pore.diameter is already present on a Geometry (e.g. pn['pore.diameter'] = 2.0 will result in an error)\n",
    "* Interleaving data is automatically attempted if the requested key is not found.  For instance, when you request ``pn['pore.diameter']`` it is not found, so a search is made of the associated Geometry objects and if found an array is built.\n",
    "* If an array named 'pore.foo' is already present on the Network or Phase, it cannot be created on a Geometry or Physics, resepctively, since this would break the automated ``interleave_data`` mechanism, which searches for arrays called 'pore.foo' on all associated objects"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
